package com.lcy.sys.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.lcy.sys.mapper.SysUserMapper;
import com.lcy.sys.model.vo.SysStatisticsResponse;
import com.lcy.sys.service.SysStatisticsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream;

import static com.lcy.sys.model.entity.table.SysUserTableDef.SYS_USER;

/**
 * 系统统计数据服务实现
 *
 * @author zhang.rx
 * @since 2024/7/15
 */
@Service
@RequiredArgsConstructor
public class SysStatisticsServiceImpl implements SysStatisticsService {

    private final SysUserMapper userMapper;
    
    @Override
    public SysStatisticsResponse getStatistics() {
        // 获取当前日期和7天前的日期
        LocalDate today = LocalDate.now();
        LocalDate sevenDaysAgo = today.minusDays(6);
        
        // 格式化日期
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
        List<String> dateRange = IntStream.rangeClosed(0, 6)
                .mapToObj(sevenDaysAgo::plusDays)
                .map(date -> date.format(formatter))
                .toList();
        
        // 查询用户总数
        int totalUsers = (int) userMapper.selectCountByQuery(new QueryWrapper());
        
        // 查询新增用户数（过去7天内注册的用户）
        LocalDateTime sevenDaysAgoDateTime = sevenDaysAgo.atStartOfDay();
        int newUsers = (int) userMapper.selectCountByQuery(
                new QueryWrapper().where(SYS_USER.CREATE_TIME.ge(sevenDaysAgoDateTime))
        );
        
        // 构造用户趋势数据（近7天的用户增长）
        // 注：这里我们假设用户总是增长的，实际项目中应该从数据库查询每天的累计用户数
        List<Integer> totalUserTrend = generateTotalUserTrend(totalUsers, 7);
        
        // 构造活跃用户数据
        // 注：实际项目中应该从登录日志或活跃记录中查询，这里使用模拟数据
        int activeUsers = simulateActiveUsers(totalUsers);
        List<Integer> activeUserTrend = simulateActiveUserTrend(totalUserTrend);
        
        // 计算活跃度趋势（活跃用户占总用户的百分比）
        List<Integer> activityTrend = calculateActivityTrend(totalUserTrend, activeUserTrend);
        
        // 计算日均活跃用户数（近7天活跃用户的平均值）
        int dailyActiveUsers = (int) activeUserTrend.stream().mapToInt(Integer::intValue).average().orElse(0);
        
        // 计算变化趋势（同比增长百分比）
        // 注：实际项目中应该与更长时间的历史数据比较，这里简化计算
        double totalUsersTrend = calculateTrend(totalUserTrend);
        double newUsersTrend = generateRandomTrend();
        double activeUsersTrend = calculateTrend(activeUserTrend);
        double dailyActiveUsersTrend = activeUsersTrend - 1.5; // 日均活跃用户趋势相对于活跃用户趋势略低
        
        // 构建响应对象
        return SysStatisticsResponse.builder()
                .totalUsers(totalUsers)
                .newUsers(newUsers)
                .activeUsers(activeUsers)
                .dailyActiveUsers(dailyActiveUsers)
                .totalUserTrend(totalUserTrend)
                .activeUserTrend(activeUserTrend)
                .activityTrend(activityTrend)
                .dateRange(dateRange)
                .totalUsersTrend(totalUsersTrend)
                .newUsersTrend(newUsersTrend)
                .activeUsersTrend(activeUsersTrend)
                .dailyActiveUsersTrend(dailyActiveUsersTrend)
                .build();
    }
    
    /**
     * 生成总用户趋势数据
     * 
     * @param currentTotal 当前总用户数
     * @param days 天数
     * @return 用户趋势数据
     */
    private List<Integer> generateTotalUserTrend(int currentTotal, int days) {
        List<Integer> trend = new ArrayList<>();
        int dailyDecrease = currentTotal / (days * 2); // 每天减少的用户数，确保合理递减
        
        for (int i = days - 1; i >= 0; i--) {
            // 最后一天是当前总数，往前递减
            int usersOnDay = Math.max(7, currentTotal - (dailyDecrease * i));
            trend.add(usersOnDay);
        }
        
        return trend;
    }
    
    /**
     * 模拟活跃用户数量
     * 
     * @param totalUsers 总用户数
     * @return 活跃用户数
     */
    private int simulateActiveUsers(int totalUsers) {
        // 活跃用户数约为总用户的60-80%
        double activeRate = ThreadLocalRandom.current().nextDouble(0.6, 0.8);
        return (int) (totalUsers * activeRate);
    }
    
    /**
     * 计算活跃度趋势
     * 
     * @param totalUserTrend 总用户趋势
     * @param activeUserTrend 活跃用户趋势
     * @return 活跃度趋势（百分比）
     */
    private List<Integer> calculateActivityTrend(List<Integer> totalUserTrend, List<Integer> activeUserTrend) {
        List<Integer> activityTrend = new ArrayList<>();
        
        for (int i = 0; i < totalUserTrend.size(); i++) {
            int total = totalUserTrend.get(i);
            int active = activeUserTrend.get(i);
            
            // 计算活跃度百分比：活跃用户数 / 总用户数 * 100
            // 直接计算实际百分比，不再强制限制在特定范围内
            int activityPercentage = (int) Math.round((active * 100.0) / total);
            activityTrend.add(activityPercentage);
        }
        
        return activityTrend;
    }
    
    /**
     * 模拟活跃用户趋势
     * 
     * @param totalUserTrend 总用户趋势
     * @return 活跃用户趋势
     */
    private List<Integer> simulateActiveUserTrend(List<Integer> totalUserTrend) {
        List<Integer> activeUserTrend = new ArrayList<>();
        
        for (Integer totalOnDay : totalUserTrend) {
            // 使用不同的活跃率，确保每天有变化
            // 改为50-75%的范围，增加数据波动性
            double activeRate = ThreadLocalRandom.current().nextDouble(0.5, 0.75);
            activeUserTrend.add((int) Math.round(totalOnDay * activeRate));
        }
        
        return activeUserTrend;
    }
    
    /**
     * 计算趋势（增长百分比）
     * 
     * @param data 数据列表
     * @return 增长百分比
     */
    private double calculateTrend(List<Integer> data) {
        if (data.size() < 2) {
            return 0.0;
        }
        
        // 计算最近增长率
        int firstValue = data.get(0);
        int lastValue = data.get(data.size() - 1);
        
        // 避免除以零
        if (firstValue == 0) {
            return 0.0;
        }
        
        // 计算增长百分比
        return Math.round(((lastValue - firstValue) * 100.0 / firstValue) * 10) / 10.0;
    }
    
    /**
     * 生成随机趋势（增长百分比）
     * 
     * @return 增长百分比
     */
    private double generateRandomTrend() {
        // 生成-5到25之间的随机增长率
        return Math.round(ThreadLocalRandom.current().nextDouble(-5, 25) * 10) / 10.0;
    }
} 